﻿using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using AutoMapper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using TyNetCoreBlog.Models.Dto.Category;
using TyNetCoreBlog.Models.Entities;
using TyNetCoreBlog.Repository.RepositoryWrapper;
using TyNetCoreBlog.Helpers;
using TyNetCoreBlog.Models.Dto.User;
using Newtonsoft.Json;
using static TyNetCoreBlog.Helpers.ResponseMsg;
using TyNetCoreBlog.Models.Dto.Blog;
using TyNetCoreBlog.Models.Data;
using System.Linq;
using TyNetCoreBlog.Models.Dto.FriendlyLink;
using TyNetCoreBlog.Models.Dto.Tag;
using Microsoft.Extensions.Logging;

namespace TyNetCoreBlog.Controllers
{
    [Route("api/admin")]
    [EnableCors("any")]
    [ApiController]
    [Authorize]
    
    public class AdminController : ControllerBase
    {
        private readonly AppDbContext _context;
        private readonly IRepositoryWrapper _repositoryWrapper;
        private readonly IMapper _mapper;
        private readonly ILogger<AdminController> _logger;

        public AdminController(AppDbContext context, IConfiguration configuration, IRepositoryWrapper repositoryWrapper,
            IMapper mapper, ILogger<AdminController> logger)
        {
            this._context = context;
            this._repositoryWrapper = repositoryWrapper ?? throw new ArgumentNullException(nameof(repositoryWrapper));
            this._mapper = mapper ?? throw new ArgumentNullException(nameof(mapper));
            this._logger = logger;
        }


        /// <summary>
        /// 后台登录
        /// </summary>
        /// <param name="userLoginParameters">登录传递过来的对象参数</param>
        /// <returns></returns>
        [AllowAnonymous]
        [HttpPost("login")]
        [ApiConventionMethod(typeof(DefaultApiConventions), nameof(DefaultApiConventions.Create))]
        public IActionResult Login([FromBody] UserLoginParameters userLoginParameters)
        {
            if (!string.IsNullOrWhiteSpace(userLoginParameters.Username) && !string.IsNullOrWhiteSpace(userLoginParameters.Password)) //不为空
            {
                var usr = _repositoryWrapper.User.Login(userLoginParameters.Username, userLoginParameters.Password);
                if (usr == null)
                {
                    return Content(JsonConvert.SerializeObject(new ResponseMsg(ApiStatus.Forbidden, "用户名或密码错误")));
                }

                var claims = new[] {
                    new Claim(ClaimTypes.Name, userLoginParameters.Username),
                    new Claim(ClaimTypes.Email, Const.Email),
                    new Claim(JwtRegisteredClaimNames.Exp, $"{new DateTimeOffset(DateTime.Now.AddMinutes(Const.Expires)).ToUnixTimeSeconds()}"),
                    new Claim(JwtRegisteredClaimNames.Nbf, $"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}")
                };

                // 创建key
                var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Const.IssuerSigningKey));
                // 创建签名证书
                var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

                var securityToken = new JwtSecurityToken(
                    // 发行者
                    issuer: Const.ValidIssuer,
                    // 接收者
                    audience: Const.ValidAudience,
                    // 声明
                    claims: claims,
                    // 过期时间
                    expires: DateTime.Now.AddMinutes(Const.Expires),
                    // 签名证书
                    signingCredentials: creds
                    );

                string token = new JwtSecurityTokenHandler().WriteToken(securityToken);
                return Ok(new { status = 200, message = "登录成功", token = token });
            }
            else
            {
                return BadRequest(new ResponseMsg(ApiStatus.BadRequest,"用户名和密码不能为空!"));
            }
        }


        /// <summary>
        /// 更新用户信息
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="userForUpdateDto"></param>
        /// <returns></returns>
        [HttpPut]
        [Route("user/{userId}")]
        [ApiConventionMethod(typeof(DefaultApiConventions), nameof(DefaultApiConventions.Create))]
        public async Task<ActionResult> UpdateUser(int userId, [FromBody] UserForUpdateDto userForUpdateDto)
        {
            var user = await _repositoryWrapper.User.GetByIdAsync(userId);
            if (user == null)
            {
                return NotFound(new ResponseMsg(ApiStatus.NotFound));
            }

            _mapper.Map(userForUpdateDto, user, typeof(UserForUpdateDto), typeof(User));
             _repositoryWrapper.User.Update(user);
            bool res = await _repositoryWrapper.User.SaveAsync();
            if (!res)   //执行更新失败
            {
                throw new Exception("用户信息更新失败");
            }
            _logger.LogWarning("用户信息被修改：", user);
            return Ok(new ResponseMsg(ApiStatus.OK));
        }


        /// <summary>
        /// 修改用户密码
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="userForChangepwd"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        [HttpPut]
        [Route("user/{userId}/changepwd")]
        [ApiConventionMethod(typeof(DefaultApiConventions), nameof(DefaultApiConventions.Create))]
        public async Task<ActionResult> ChangePwd(int userId, [FromBody] UserForChangepwd userForChangepwd)
        {
            var user = await _repositoryWrapper.User.GetByIdAsync(userId);
            if (user == null)
            {
                return NotFound(new ResponseMsg(ApiStatus.NotFound));
            }

            _context.Users.Attach(user);
            user.Password = Md5Encrypt.GetMd5Str(userForChangepwd.Password);
            bool res = _context.SaveChanges() > 0;
            if (!res)
            {
                throw new Exception("修改密码失败");
            }
            _logger.LogWarning($"用户密码被修改：{user.Password}");
            return Ok(new ResponseMsg(ApiStatus.OK));
        }
        

        /// <summary>
        /// 创建一个分类
        /// </summary>
        /// <param name="categoryForCreationDto"></param>
        /// <returns></returns>
        [HttpPost]
        [Route("category")]
        [ApiConventionMethod(typeof(DefaultApiConventions), nameof(DefaultApiConventions.Create))]
        public async Task<ActionResult<CategoryDto>> AddCate(CategoryForCreationDto categoryForCreationDto)
        {
            var isExit = _repositoryWrapper.Category.NameIsExits(categoryForCreationDto.Name);
            if (isExit) //名称已存在
            {
                Response.StatusCode = (int)ApiStatus.AlreadyExists;
                return Content(JsonConvert.SerializeObject(new ResponseMsg(ApiStatus.AlreadyExists)), Const.RESPCONTENTTYPE, Encoding.UTF8);
            }
            var cate = _mapper.Map<Category>(categoryForCreationDto);
            _repositoryWrapper.Category.Create(cate);
            bool res = await _repositoryWrapper.Category.SaveAsync();
            if (!res)   //保存失败
            {
                throw new Exception("分类创建失败");
            }

            var cateCreated = _mapper.Map<CategoryDto>(cate);
            _logger.LogWarning("创建了一个分类：", cateCreated);
            return CreatedAtRoute(nameof(CategoryController.GetOneCategory),
                new { cateId = cateCreated.Id }, cateCreated);
        }



        /// <summary>
        /// 删除一个分类
        /// </summary>
        /// <param name="cateId">cateId</param>
        /// <returns></returns>
        [HttpDelete]
        [Route("category/{cateId}")]
        [ApiConventionMethod(typeof(DefaultApiConventions), nameof(DefaultApiConventions.Create))]
        public async Task<ActionResult> DeleteOneCate(int cateId) 
        {
            var cate = await _repositoryWrapper.Category.GetByIdAsync(cateId);
            if (cate == null)
            {
                return NotFound(new ResponseMsg(ApiStatus.NotFound));
            }

            _repositoryWrapper.Category.Delete(cate);
            bool res = await _repositoryWrapper.Category.SaveAsync();
            if (!res)   //执行删除失败
            {
                throw new Exception("分类删除失败");
            }
            _logger.LogWarning("删除了一个分类：", cate);
            return Ok(new ResponseMsg(ApiStatus.OK));
        }


        /// <summary>
        /// 更新一个分类
        /// </summary>
        /// <param name="cateId">cateId</param>
        /// <param name="categoryFroUpdateDto">提交更新的实体对象</param>
        /// <returns></returns>
        [HttpPut]
        [Route("category/{cateId}")]
        [ApiConventionMethod(typeof(DefaultApiConventions), nameof(DefaultApiConventions.Create))]
        public async Task<ActionResult> UpdateCate(int cateId, [FromBody] CategoryFroUpdateDto categoryFroUpdateDto)
        {
            var cate = await _repositoryWrapper.Category.GetByIdAsync(cateId);
            if (cate == null)
            {
                return NotFound(new ResponseMsg(ApiStatus.NotFound));
            }
            // 名称已存在
            if (string.Equals(cate.Name, categoryFroUpdateDto.Name, StringComparison.CurrentCulture))
            {
                Response.StatusCode = (int)ApiStatus.AlreadyExists;
                return Content(JsonConvert.SerializeObject(new ResponseMsg(ApiStatus.AlreadyExists)), Const.RESPCONTENTTYPE, Encoding.UTF8);
            }

            _mapper.Map(categoryFroUpdateDto, cate, typeof(CategoryFroUpdateDto), typeof(Category));
            _repositoryWrapper.Category.Update(cate);
            bool res = await _repositoryWrapper.Category.SaveAsync();
            if (!res)   //执行更新失败
            {
                throw new Exception("分类信息更新失败");
            }
            _logger.LogWarning("分类信息被更新：", cate);
            return Ok(new ResponseMsg(ApiStatus.OK));
        }




        /// <summary>
        /// 添加一个博客
        /// </summary>
        /// <param name="blogForCreationDto">提交的待创建博客实体</param>
        /// <returns></returns>
        [HttpPost]
        [Route("blog")]
        [ApiConventionMethod(typeof(DefaultApiConventions), nameof(DefaultApiConventions.Create))]
        public async Task<ActionResult<BlogDto>> AddBlog([FromBody] BlogForCreationDto blogForCreationDto)
        {
            var blog = _mapper.Map<Blog>(blogForCreationDto);
            if (blogForCreationDto.UserId < 1){ blog.UserId = 1; }    //设置userID
            blog.CreateTime = DateTime.Now;
            blog.UpdateTime = DateTime.Now;
            _repositoryWrapper.Blog.Create(blog);
            bool res = await _repositoryWrapper.Blog.SaveAsync();
            if(!res)   //保存失败
            {
                throw new Exception("添加博客失败");
            }
            var blogCreated = _mapper.Map<BlogDto>(blog);

            //设置关联的tagId
            if (blogForCreationDto.TagIds != null)
            {
                foreach (var tid in blogForCreationDto.TagIds)
                {
                    _context.Set<BlogTag>().Add(new BlogTag
                    {
                        BlogId = blogCreated.Id,
                        TagId = Convert.ToInt32(tid),
                    });
                }
                _context.SaveChanges();
            }
            _logger.LogWarning("添加了一篇博客文章：", blogCreated);
            return CreatedAtRoute(nameof(BlogsController.GetBlogDetail),
                new { blogId = blogCreated.Id }, blogCreated);
        }


        /// <summary>
        /// 删除一个博客
        /// </summary>
        /// <param name="blogId"></param>
        /// <returns></returns>
        [HttpDelete]
        [Route("blog/{blogId}")]
        [ApiConventionMethod(typeof(DefaultApiConventions), nameof(DefaultApiConventions.Create))]
        public async Task<ActionResult> DeleteOneBlog(int blogId)
        {
            var blog = await _repositoryWrapper.Blog.GetByIdAsync(blogId);
            if (blog == null)
            {
                return NotFound(new ResponseMsg(ApiStatus.NotFound));
            }

            _repositoryWrapper.Blog.Delete(blog);
            bool res = await _repositoryWrapper.Blog.SaveAsync();
            if (!res)   //执行删除失败
            {
                throw new Exception("删除博客失败");
            }
            _logger.LogWarning("删除了一篇博客文章：", blog);
            return Ok(new ResponseMsg(ApiStatus.OK));
        }


        /// <summary>
        /// 更新博客
        /// </summary>
        /// <param name="blogId"></param>
        /// <param name="blogForUpdateDto">提交更新的blog实体</param>
        /// <returns></returns>
        [HttpPut]
        [Route("blog/{blogId}")]
        [ApiConventionMethod(typeof(DefaultApiConventions), nameof(DefaultApiConventions.Create))]
        public async Task<ActionResult> UpdateOneBlog(int blogId, [FromBody] BlogForUpdateDto blogForUpdateDto)
        {
            var b = await _repositoryWrapper.Blog.GetByIdAsync(blogId);
            if (b == null)
            {
                return NotFound(new ResponseMsg(ApiStatus.NotFound));
            }

            var blog = _mapper.Map<BlogForUpdateDto, Blog>(blogForUpdateDto, b);
            if (blog.UserId < 1){ blog.UserId = 1; }    //设置userID
            blog.UpdateTime = DateTime.Now;
            _repositoryWrapper.Blog.Update(blog);

            bool res = await _repositoryWrapper.Blog.SaveAsync();
            if (!res)   //执行更新失败
            {
                throw new Exception("更新博客信息失败");
            }

            //设置关联的TagId关系----------------------------------
            if (blogForUpdateDto.TagIds != null)
            {
                //删除原有关系
                var bts = _context.Set<BlogTag>()
                    .Where(x => x.BlogId == b.Id).ToList();
                _context.Set<BlogTag>().RemoveRange(bts);

                //设置新的关系
                foreach (var tid in blogForUpdateDto.TagIds)
                {
                    _context.Set<BlogTag>().Add(new BlogTag
                    {
                        BlogId = blog.Id,
                        TagId = Convert.ToInt32(tid),
                    });
                }
                _context.SaveChanges();
            }
            //-----------------------------------------------------
            _logger.LogWarning("博客文章被更新：" ,blog);
            return Ok(new ResponseMsg(ApiStatus.OK));
        }


        /// <summary>
        /// 创建一个标签
        /// </summary>
        /// <param name="tagForCreationDto"></param>
        /// <returns></returns>
        [HttpPost]
        [Route("tag")]
        [ApiConventionMethod(typeof(DefaultApiConventions), nameof(DefaultApiConventions.Create))]
        public async Task<ActionResult<TagDto>> AddTag(TagForCreationDto tagForCreationDto)
        {
            //判断是否存在
            var isExit = _repositoryWrapper.Tag.NameIsExits(tagForCreationDto.Name);
            if (isExit) //名称已存在
            {
                Response.StatusCode = (int)ApiStatus.AlreadyExists;
                return Content(JsonConvert.SerializeObject(new ResponseMsg(ApiStatus.AlreadyExists)), Const.RESPCONTENTTYPE, Encoding.UTF8);
            }
            var tag = _mapper.Map<Tag>(tagForCreationDto);
            _repositoryWrapper.Tag.Create(tag);
            bool res = await _repositoryWrapper.Tag.SaveAsync();
            if (!res)   //保存失败
            {
                throw new Exception("创建标签失败");
            }

            var tagCreated = _mapper.Map<TagDto>(tag);
            _logger.LogWarning("创建了一个标签：" ,tagForCreationDto);
            return CreatedAtRoute(nameof(TagsController.GetOneTag),
                new { tagId = tagCreated.Id }, tagCreated);
        }


        /// <summary>
        /// 删除一个标签
        /// </summary>
        /// <param name="tagId">tagId</param>
        /// <returns></returns>
        [HttpDelete]
        [Route("tag/{tagId}")]
        [ApiConventionMethod(typeof(DefaultApiConventions), nameof(DefaultApiConventions.Create))]
        public async Task<ActionResult> DeleteOneTag(int tagId)
        {
            var tag = await _repositoryWrapper.Tag.GetByIdAsync(tagId);
            if (tag == null)
            {
                return NotFound(new ResponseMsg(ApiStatus.NotFound));
            }
            _repositoryWrapper.Tag.Delete(tag);
            bool res = await _repositoryWrapper.Tag.SaveAsync();
            if (!res)   //执行删除失败
            {
                throw new Exception("删除标签失败");
            }
            _logger.LogWarning("删除了一个标签：", tag);
            return Ok(new ResponseMsg(ApiStatus.OK));
        }


        /// <summary>
        /// 更新新一个标签
        /// </summary>
        /// <param name="tagId">TagId</param>
        /// <param name="tagForUpdateDto">提交更新的实体对象</param>
        /// <returns></returns>
        [HttpPut]
        [Route("tag/{tagId}")]
        [ApiConventionMethod(typeof(DefaultApiConventions), nameof(DefaultApiConventions.Create))]
        public async Task<ActionResult> UpdateTag(int tagId, [FromBody] TagForUpdateDto tagForUpdateDto)
        {
            var tag = await _repositoryWrapper.Tag.GetByIdAsync(tagId);
            if (tag == null)
            {
                return NotFound(new ResponseMsg(ApiStatus.NotFound));
            }
            // 名称已存在
            if (string.Equals(tag.Name, tagForUpdateDto.Name, StringComparison.CurrentCulture))
            {
                Response.StatusCode = (int)ApiStatus.AlreadyExists;
                return Content(JsonConvert.SerializeObject(new ResponseMsg(ApiStatus.AlreadyExists)), Const.RESPCONTENTTYPE, Encoding.UTF8);
            }

            _mapper.Map(tagForUpdateDto, tag, typeof(TagForUpdateDto), typeof(Tag));
            _repositoryWrapper.Tag.Update(tag);
            bool res = await _repositoryWrapper.Tag.SaveAsync();
            if (!res)   //执行更新失败
            {
                throw new Exception("更新标签信息失败");
            }
            _logger.LogWarning("一个标签被更新：", tag);
            return Ok(new ResponseMsg(ApiStatus.OK));
        }


        
        /// <summary>
        /// 创建一个友链
        /// </summary>
        /// <param name="friendlyLinkForCreationDto">提交的待创建的实体对象</param>
        /// <returns>返回创建的友链URL、实体信息</returns>
        [HttpPost]
        [Route("friendlylink")]
        [ApiConventionMethod(typeof(DefaultApiConventions), nameof(DefaultApiConventions.Create))]
        public async Task<ActionResult<FriendlyLinkDto>> AddFriendlylink(FriendlyLinkForCreationDto friendlyLinkForCreationDto)
        {
            var flink = _mapper.Map<FriendlyLink>(friendlyLinkForCreationDto);
            _repositoryWrapper.Friendlylink.Create(flink);
            bool res = await _repositoryWrapper.Friendlylink.SaveAsync();
            if (!res)   //保存失败
            {
                throw new Exception("创建友链失败");
            }

            var flinkCreated = _mapper.Map<FriendlyLinkDto>(flink);
            _logger.LogWarning("创建了一个友链：", flinkCreated);
            return CreatedAtRoute("GetOneFriendlylink",
                new { flinkId = flinkCreated.Id }, flinkCreated);
        }
        
        
        /// <summary>
        /// 删除一个友链
        /// </summary>
        /// <param name="flinkId"></param>
        /// <returns></returns>
        [HttpDelete]
        [Route("friendlylink/{flinkId}")]
        [ApiConventionMethod(typeof(DefaultApiConventions), nameof(DefaultApiConventions.Create))]
        public async Task<ActionResult> DeleteOneFriendlylink(int flinkId)
        {
            var flink = await _repositoryWrapper.Friendlylink.GetByIdAsync(flinkId);
            if (flink == null)
            {
                return NotFound(new ResponseMsg(ApiStatus.NotFound));
            }
            _repositoryWrapper.Friendlylink.Delete(flink);
            bool res = await _repositoryWrapper.Friendlylink.SaveAsync();
            if (!res)   //执行删除失败
            {
                throw new Exception("删除友链失败");
            }
            _logger.LogWarning("一个友链被删除：", flink);
            return Ok(new ResponseMsg(ApiStatus.OK));
        }
        
        
        /// <summary>
        /// 更新一个友链信息
        /// </summary>
        /// <param name="flinkId"></param>
        /// <param name="friendlyLinkForUpdateDto"></param>
        /// <returns></returns>
        [HttpPut]
        [Route("friendlylink/{flinkId}")]
        [ApiConventionMethod(typeof(DefaultApiConventions), nameof(DefaultApiConventions.Create))]
        public async Task<ActionResult> UpdateFriendlylink(int flinkId, [FromBody] FriendlyLinkForUpdateDto friendlyLinkForUpdateDto)
        {
            var flink = await _repositoryWrapper.Friendlylink.GetByIdAsync(flinkId);
            if (flink == null)
            {
                return NotFound(new ResponseMsg(ApiStatus.NotFound));
            }
            
            _mapper.Map(friendlyLinkForUpdateDto, flink, typeof(FriendlyLinkForUpdateDto), typeof(FriendlyLink));
            _repositoryWrapper.Friendlylink.Update(flink);
            bool res = await _repositoryWrapper.Friendlylink.SaveAsync();
            if (!res)   //执行更新失败
            {
                throw new Exception("更新友链信息失败");
            }
            _logger.LogWarning("一个友链信息被更新：", flink);
            return Ok(new ResponseMsg(ApiStatus.OK));
        }
        
    }
}
